package it.polimi.TravelDream.ejb.searchManager;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import it.polimi.TravelDream.ejb.dtos.AddressDTO;
import it.polimi.TravelDream.ejb.dtos.ExcursionDTO;
import it.polimi.TravelDream.ejb.dtos.FlightDTO;
import it.polimi.TravelDream.ejb.dtos.HotelDTO;
import it.polimi.TravelDream.ejb.dtos.PackageDTO;
import it.polimi.TravelDream.ejb.dtos.RoomDTO;
import it.polimi.TravelDream.ejb.dtos.UserDTO;
import it.polimi.TravelDream.ejb.entities.Address;
import it.polimi.TravelDream.ejb.entities.BasicPackage;
import it.polimi.TravelDream.ejb.entities.Excursion;
import it.polimi.TravelDream.ejb.entities.Flight;
import it.polimi.TravelDream.ejb.entities.Hotel;
import it.polimi.TravelDream.ejb.entities.Room;
import it.polimi.TravelDream.ejb.entities.User;
import it.polimi.TravelDream.ejb.entities.UserPackage;

import javax.annotation.Resource;
import javax.ejb.EJBContext;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

/**
 * Session Bean implementation class PersonalizationManager
 */
@Stateless
public class PersonalizationManager implements PersonalizationMgr {

	@PersistenceContext
    private EntityManager em;
	@Resource
	private EJBContext context;
	private BasicPackage selectedPackage=new BasicPackage();
	private List<Room> selectedRooms=new ArrayList<Room>();
	private List <Flight> selectedFlightList = new ArrayList<Flight>();
	private List<Hotel> hotelList= new ArrayList<Hotel>();
	private List<Excursion> selectedExcursions=new ArrayList<Excursion>();
	private String departureCity;
	private Date departureDate;
	private Date arrivalDate;
	private Hotel selectedHotel=new Hotel();

    /**
     * Default constructor. 
     */
    public PersonalizationManager() {
        // TODO Auto-generated constructor stub
    }
    
    @Override
    public void setEmptyFlightList(){
    	this.selectedFlightList = new ArrayList<Flight>();
    }
    
    //setta il package selezionato a partire dal DTO
    @Override
    public void setSelectedPackage(PackageDTO packageDTO){
    	this.selectedPackage = em.createNamedQuery(BasicPackage.FIND_PACKAGES_BY_TRAVELID,BasicPackage.class).setParameter("travelID", packageDTO.getTravelID()).getSingleResult();
    }
   
    //setta l'hotel selezionato a partire dal DTO
    @Override
    public void setSelectedHotel(HotelDTO hotelDTO){
    	this.selectedHotel = em.createNamedQuery(Hotel.FIND_BY_HOTELID,Hotel.class).setParameter("hotelID", hotelDTO.getHotelID()).getSingleResult();
    }
    
    @Override
    public PackageDTO getSelectedPackage(){
    	PackageDTO packageDTO = convertToDTO(selectedPackage);
    	return packageDTO;
    }
    
    @Override
    public HotelDTO getSelectedHotel(){
    	AddressDTO addressDTO = convertAddressToDTO(selectedHotel.getHotelAddress());
    	HotelDTO hotelDTO = convertHotelToDTO(this.selectedHotel,addressDTO);
    	return hotelDTO;
    }
    
    @Override   
    public void searchHotel(){
    	List<Hotel> allHotels = new ArrayList<Hotel>();//room del package selezionato
    	allHotels = em.createNamedQuery(Hotel.FIND_ALL_HOTEL, Hotel.class).getResultList();
			for(Room r: selectedPackage.getRooms()){
				for(Hotel h: allHotels){
					if(h.getHotelID()==r.getHotelName().getHotelID()){
						if(!hotelListContains(h, hotelList))
							hotelList.add(h);
						}
					}	
			}
    }


    
    @Override
    public void addFlight(FlightDTO flightDTO) {
    	Flight flight = new Flight();
    	flight = em.find(Flight.class, flightDTO.getFlightID());
    	
    	if(!selectedFlightList.contains(flight)) {
    		flight.setAvailable(false);
    		em.merge(flight);
    		selectedFlightList.add(flight);
    		}
    	}

    @Override
    public void removeFlight(FlightDTO flightDTO) {
    	Flight flight = new Flight();
    	flight = em.find(Flight.class, flightDTO.getFlightID());
    	
    	if(selectedFlightList.contains(flight)) {
    		selectedFlightList.remove(flight);
    	}
    }

 	//restituisce una lista di FlightDTO che corrisponde alla lista degli aerei di ritorno

 
 	//restituisce una lista di FlightDTO che corrisponde alla lista degli aerei di andata

 	@Override	
 	public void setExcursions(List<ExcursionDTO> dtosList){
 		this.selectedExcursions = new ArrayList<Excursion>();
 		for(ExcursionDTO dto:dtosList){
 			Excursion e = em.createNamedQuery(Excursion.FIND_EXCURSION_BY_EXCURSIONID, Excursion.class).setParameter("excursionID",dto.getExcursionId()).getSingleResult();
 			this.selectedExcursions.add(e);
 		}
 	}
 	
 	@Override
 	public boolean selectRoom(int bedNumber){
 		List<Room> roomTemp= em.createNamedQuery(Room.FIND_ROOM_BY_HOTEL_AND_BEDS, Room.class).setParameter("hotelName", this.selectedHotel).setParameter("beds", bedNumber).getResultList();
 	if(roomTemp.size()!=0){
 		for (Room r:roomTemp){
 						this.selectedRooms.add(r);
 						r.setAvailable(false);
 						em.merge(r);
 						System.out.print("size della roomList");
 						System.out.println(this.selectedRooms.size());
 						return true;
 					}
 		}
 		return false;
 	}
 	
 	@Override
 	public List <RoomDTO> getRoomsResultList(){
 		 return convertRoomList(this.selectedRooms);
 	}
    
 	@Override
 	public void createUserPackage(UserDTO userdto){
 		List<User> userList = new ArrayList<User>();
 		userList.add(em.find(User.class,userdto.getUsername()));
 		UserPackage userPackage = new UserPackage();
 		userPackage.setName(selectedPackage.getName());
 		userPackage.setDescription(selectedPackage.getDescription());
 		userPackage.setRooms(selectedRooms);
 		userPackage.setCity(selectedPackage.getCity());
 		userPackage.setNation(selectedPackage.getNation());
 		userPackage.setStartingDate(this.departureDate);
 		userPackage.setExpirationDate(this.arrivalDate);
 		userPackage.setList_of_flight(selectedFlightList);
 		userPackage.setUsers_who_booked(userList);
 		userPackage.setExcursions(this.selectedPackage.getExcursions());
 		em.persist(userPackage);
 	}
 	
 	//restituisce una lista di HotelDTO che corrisponde alla lista di hotel disponibili per quel determinato pacchetto
 	@Override
    public List <HotelDTO> getHotelResultList(){
   	   List <HotelDTO> hotelDTOs = new ArrayList <HotelDTO>();
      	
  	 	   for(Hotel h:hotelList){
  	 		AddressDTO addressDTO=convertAddressToDTO(h.getHotelAddress());
  	 		HotelDTO hotelDTO = convertHotelToDTO(h,addressDTO);
  	 		hotelDTOs.add(hotelDTO);
  	 	   }
  	 	   return hotelDTOs;
      }

 	//restituisce la citta di partenza
 	@Override
	public String getDepartureCity() {
		return departureCity;
	}

 	//setta il valore della citta di partenza scelta
 	@Override
	public void setDepartureCity(String departureCity) {
		this.departureCity = departureCity;
	}

 	//restituisce la data di partenza
 	@Override
	public Date getDepartureDate() {
		return departureDate;
	}

 	//setta la data di partenza
 	@Override
	public void setDepartureDate(Date departureDate) {
		this.departureDate = departureDate;
	}

 	//restituisce la data di ritorno
 	@Override
	public Date getArrivalDate() {
		return arrivalDate;
	}

 	//setta la data di ritorno
 	@Override
	public void setArrivalDate(Date arrivalDate) {
		this.arrivalDate = arrivalDate;
 	}

	private PackageDTO convertToDTO (BasicPackage basicPackage){
    	PackageDTO packageDTO = new PackageDTO();
    	packageDTO.setTravelID(basicPackage.getTravelID());
    	packageDTO.setName(basicPackage.getName());
    	packageDTO.setCity(basicPackage.getCity());
    	packageDTO.setDescription(basicPackage.getDescription());
    	packageDTO.setExcursions(convertExcursionList(basicPackage.getExcursions()));
    	packageDTO.setFlights(convertFlightList(basicPackage.getFlights()));
    	packageDTO.setRooms(convertRoomList(basicPackage.getRooms()));
    	packageDTO.setLastMinute(basicPackage.getLastMinute());
    	packageDTO.setExpirationDate(basicPackage.getExpirationDate());
    	packageDTO.setStartingDate(basicPackage.getStartingDate());
    
    	packageDTO.setNation(basicPackage.getNation());
    	return packageDTO;
    }
    
    private FlightDTO convertFlightToDTO (Flight flight){
    	FlightDTO flightDTO = new FlightDTO();
    	flightDTO.setArrivalAirport(flight.getArrivalAirport());
    	flightDTO.setArrivalCity(flight.getArrivalCity());
    	flightDTO.setDepartureAirport(flight.getDepartureAirport());
    	flightDTO.setDepartureCity(flight.getDepartureCity());
    	flightDTO.setDepartureDate(flight.getDepartureDate());
    	flightDTO.setPrice(flight.getPrice());
    	flightDTO.setSeat(flight.getSeat());
    	return flightDTO;
    }
    
    private List<FlightDTO> convertFlightList(List<Flight> flights){
    	
    	List<FlightDTO> fdtos = new ArrayList<FlightDTO>();
    	for(Flight f : flights){
    		fdtos.add(convertFlightToDTO(f));
    	}
    	return fdtos;
    }
    
    private ExcursionDTO convertExcursionToDTO (Excursion excursion){
    	ExcursionDTO excursionDTO = new ExcursionDTO();
    	excursionDTO.setName(excursion.getName());
    	excursionDTO.setDescription(excursion.getDescription());
    	excursionDTO.setNation(excursion.getNation());
    	excursionDTO.setPlacesAvailable(excursion.getPlacesAvailable());
    	excursionDTO.setPrice(excursion.getPrice());
    	
    	return excursionDTO;
    }
    
    private List<ExcursionDTO> convertExcursionList(List<Excursion> excursions){
    	
    	List<ExcursionDTO> edtos = new ArrayList<ExcursionDTO>();
    	for(Excursion e : excursions){
    		edtos.add(convertExcursionToDTO(e));
    	}
    	return edtos;
    }
 
    private RoomDTO convertRoomToDTO(Room room){
    	RoomDTO roomDTO = new RoomDTO();
    	roomDTO.setRoomNumber(room.getRoomNumber());
    	roomDTO.setBeds(room.getBeds());
    	roomDTO.setPrice(room.getPrice());
    	roomDTO.setHotelName(room.getHotelName().getName());
    	return roomDTO;
    }
    
 private List<RoomDTO> convertRoomList(List<Room> rooms){
    	
    	List<RoomDTO> rdtos = new ArrayList<RoomDTO>();
    	for(Room r : rooms){
    		rdtos.add(convertRoomToDTO(r));
    	}
    	return rdtos;
    }
 
 	private AddressDTO convertAddressToDTO (Address a){
 	AddressDTO addressDTO = new AddressDTO();
 	addressDTO.setStreet(a.getStreet());
 	addressDTO.setStreetNumber(a.getStreetNumber());
 	addressDTO.setCity(a.getCity());
 	addressDTO.setCap(a.getCap());
 	addressDTO.setDistrict(a.getDistrict());
 	addressDTO.setNation(a.getNation());
 	return addressDTO;
 }

	private HotelDTO convertHotelToDTO(Hotel h, AddressDTO addressDTO){
    	HotelDTO hotelDTO = new HotelDTO();
    	hotelDTO.setHotelID(h.getHotelID());
    	hotelDTO.setName(h.getName());
    	hotelDTO.setStars(h.getStars());
    	hotelDTO.setAddressDTO(addressDTO);
    	return hotelDTO;
    }
	
	private boolean hotelListContains(Hotel hotel,List<Hotel> hotelList){
		for(Hotel h:hotelList){
			if(h.getHotelID()==hotel.getHotelID()){
				return true;
			}
		}
		return false;
	}
}